Setup Notebook¶

In [1]:
# Import 3rd party libraries
import os
import json
import requests
import numpy as np
import pandas as pd
import seaborn as sns
import geopandas as gpd
import matplotlib.pyplot as plt

# Configure Notebook
%matplotlib inline
plt.style.use('fivethirtyeight')
sns.set_context("notebook")
import warnings
warnings.filterwarnings('ignore')
ERROR 1: PROJ: proj_create_from_database: Open of /opt/conda/share/proj failed

1. Get Station Data¶

First, let's get the station information from https://tor.publicbikesystem.net. Remember, we learned about requests in Week 3.

In [2]:
response = requests.get('https://tor.publicbikesystem.net/ube/gbfs/v1/en/station_information')
bikeshare_stations = pd.DataFrame(json.loads(response.content)['data']['stations'])[['station_id', 'name', 'lat', 'lon', 'capacity']].astype({'station_id': 'int',})
bikeshare_stations = bikeshare_stations.rename(columns={'station_id': 'Station Id', 
                                                        'name': 'Station Name'})

# View DataFrame
bikeshare_stations.head()
Out[2]:
Station Id Station Name lat lon capacity
0 7000 Fort York Blvd / Capreol Ct 43.639832 -79.395954 35
1 7001 Wellesley Station Green P 43.664964 -79.383550 17
2 7002 St. George St / Bloor St W 43.667333 -79.399429 19
3 7003 Madison Ave / Bloor St W 43.667158 -79.402761 15
4 7004 University Ave / Elm St 43.656518 -79.389099 11

2. Import Toronto Neighbourhoods shapefile¶

The shapefile for City of Toronto neighbourhood boundaries 'toronto_neighbourhoods.shp' is included in the assignment directory. Use gpd.read_file() to open it and save its contents to a new variables called neighbourhoods. Make note of the 'geometry' column. This is what makes a DataFrame a Geopandas GeoDataFrame.

In [3]:
# Write your code here.
neighbourhoods = gpd.read_file('toronto_neighbourhoods.shp')

# View GeoDataFrame
neighbourhoods.head()
Out[3]:
FIELD_1 FIELD_2 FIELD_3 FIELD_4 FIELD_5 FIELD_6 FIELD_7 FIELD_8 FIELD_9 FIELD_10 FIELD_11 FIELD_12 FIELD_13 FIELD_14 FIELD_15 geometry
0 2101 25886861 25926662 49885 94 94 Wychwood (94) Wychwood (94) None None -79.425515 43.676919 16491505 3.217960e+06 7515.779658 POLYGON ((-79.43592 43.68015, -79.43492 43.680...
1 2102 25886820 25926663 49885 100 100 Yonge-Eglinton (100) Yonge-Eglinton (100) None None -79.403590 43.704689 16491521 3.160334e+06 7872.021074 POLYGON ((-79.41096 43.70408, -79.40962 43.704...
2 2103 25886834 25926664 49885 97 97 Yonge-St.Clair (97) Yonge-St.Clair (97) None None -79.397871 43.687859 16491537 2.222464e+06 8130.411276 POLYGON ((-79.39119 43.68108, -79.39141 43.680...
3 2104 25886593 25926665 49885 27 27 York University Heights (27) York University Heights (27) None None -79.488883 43.765736 16491553 2.541821e+07 25632.335242 POLYGON ((-79.50529 43.75987, -79.50488 43.759...
4 2105 25886688 25926666 49885 31 31 Yorkdale-Glen Park (31) Yorkdale-Glen Park (31) None None -79.457108 43.714672 16491569 1.156669e+07 13953.408098 POLYGON ((-79.43969 43.70561, -79.44011 43.705...

neighbourhoods contains a number of columns we don't need and with generic names. Drop all columns except for 'geometry', and 'FIELD_8'. Next, change the name of column 'FIELD_8' to 'name'. Lastly, remove the neighbourhood id from the name. For example, 'Yorkdale-Glen Park (31)' should become 'Yorkdale-Glen Park'.

In [4]:
# Drop all columns except for 'geometry', and 'FIELD_8'
neighbourhoods = neighbourhoods.drop(columns = ['FIELD_1','FIELD_2','FIELD_3','FIELD_4','FIELD_5',
                                               'FIELD_6','FIELD_7','FIELD_9','FIELD_10','FIELD_11',
                                               'FIELD_12','FIELD_13','FIELD_14','FIELD_15'])

# Change the name of column 'FIELD_8' to 'name'
neighbourhoods = neighbourhoods.rename(columns = {'FIELD_8':'name'})

# Remove the neighbourhood id from the name (use 'expand' to access only name)
neighbourhoods['name'] = neighbourhoods['name'].str.split("(", expand = True)[0]

# View GeoDataFrame
neighbourhoods.head()
Out[4]:
name geometry
0 Wychwood POLYGON ((-79.43592 43.68015, -79.43492 43.680...
1 Yonge-Eglinton POLYGON ((-79.41096 43.70408, -79.40962 43.704...
2 Yonge-St.Clair POLYGON ((-79.39119 43.68108, -79.39141 43.680...
3 York University Heights POLYGON ((-79.50529 43.75987, -79.50488 43.759...
4 Yorkdale-Glen Park POLYGON ((-79.43969 43.70561, -79.44011 43.705...

Because we're working in a relatively small area (Toronto) and we'll be looking at areas and distances, we should transform to a 2D projection crs. The City of Mississauga distributes datasets in UTM NAD83 Zone 17N (EPSG:26917) so let's try that. Transform neighbourhoods, bikeshare_stations_gdf, and bike_lanes to EPSG:26917.

In [5]:
# Transform neighbourhoods, bikeshare_stations_gdf, and bike_lanes to EPSG:26917
neighbourhoods = neighbourhoods.to_crs(epsg = 26917)

3. load bike utilization data for plot¶

In [6]:
asdf = os.getcwd()
print(asdf)
/home/jovyan/CIV1498-winter-2022-material/P2 plot
In [7]:
bike_util = pd.read_csv('Bike_Census_Utilization.csv')
bike_util.head()
Out[7]:
Neighbourhood BikeShare Rides Census Rides Rider Utilization
0 Annex 88425 1675 0.020226
1 Bathurst Manor 263 15 0.006718
2 Bay Street Corridor 509735 325 0.600925
3 Birchcliffe-Cliffside 92 140 0.000252
4 Blake-Jones 1219 305 0.001531
In [8]:
bike_util_to_merge = bike_util
bike_util_to_merge = bike_util_to_merge.drop(columns = ['BikeShare Rides','Census Rides'])
bike_util_to_merge.head()
Out[8]:
Neighbourhood Rider Utilization
0 Annex 0.020226
1 Bathurst Manor 0.006718
2 Bay Street Corridor 0.600925
3 Birchcliffe-Cliffside 0.000252
4 Blake-Jones 0.001531
In [9]:
neighbourhoods['name'] = neighbourhoods['name'].str.rstrip()
In [10]:
neigh_RU = neighbourhoods.merge(bike_util_to_merge, how = "left", left_on = "name", right_on = "Neighbourhood")
neigh_RU = neigh_RU.drop(columns = ["Neighbourhood"])
neigh_RU.head()
Out[10]:
name geometry Rider Utilization
0 Wychwood POLYGON ((626071.503 4837537.756, 626151.708 4... 0.011350
1 Yonge-Eglinton POLYGON ((628032.302 4840233.689, 628139.346 4... 0.017046
2 Yonge-St.Clair POLYGON ((629674.232 4837709.743, 629657.497 4... 0.005554
3 York University Heights POLYGON ((620320.085 4846288.688, 620352.534 4... 0.001706
4 Yorkdale-Glen Park POLYGON ((625714.291 4840359.316, 625680.263 4... NaN

4. Interactive Maps¶

In [11]:
# install folium
!pip install folium
Requirement already satisfied: folium in /opt/conda/lib/python3.8/site-packages (0.12.1.post1)
Requirement already satisfied: branca>=0.3.0 in /opt/conda/lib/python3.8/site-packages (from folium) (0.4.2)
Requirement already satisfied: requests in /opt/conda/lib/python3.8/site-packages (from folium) (2.24.0)
Requirement already satisfied: jinja2>=2.9 in /opt/conda/lib/python3.8/site-packages (from folium) (3.0.3)
Requirement already satisfied: numpy in /opt/conda/lib/python3.8/site-packages (from folium) (1.22.3)
Requirement already satisfied: idna<3,>=2.5 in /opt/conda/lib/python3.8/site-packages (from requests->folium) (2.10)
Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.8/site-packages (from requests->folium) (2021.10.8)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/conda/lib/python3.8/site-packages (from requests->folium) (1.25.10)
Requirement already satisfied: chardet<4,>=3.0.2 in /opt/conda/lib/python3.8/site-packages (from requests->folium) (3.0.4)
Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.8/site-packages (from jinja2>=2.9->folium) (2.1.1)
In [12]:
# import folium
import folium

Choropleth Plots¶

In [13]:
plot_geography = neigh_RU.to_crs(epsg=4326)[['name', 'geometry']]
plot_geography = plot_geography.set_index('name')
plot_geography.head()
Out[13]:
geometry
name
Wychwood POLYGON ((-79.43592 43.68015, -79.43492 43.680...
Yonge-Eglinton POLYGON ((-79.41096 43.70408, -79.40962 43.704...
Yonge-St.Clair POLYGON ((-79.39119 43.68108, -79.39141 43.680...
York University Heights POLYGON ((-79.50529 43.75987, -79.50488 43.759...
Yorkdale-Glen Park POLYGON ((-79.43969 43.70561, -79.44011 43.705...

Next, we'll create a DataFrame from neighbourhoods containing the quanity we want to plot 'Rider Utilization' and the neighbourhood name, which should match the index of plot_geography.

In [14]:
plot_data = neigh_RU[['name', 'Rider Utilization']]
plot_data.head()
Out[14]:
name Rider Utilization
0 Wychwood 0.011350
1 Yonge-Eglinton 0.017046
2 Yonge-St.Clair 0.005554
3 York University Heights 0.001706
4 Yorkdale-Glen Park NaN
In [15]:
from folium import Choropleth
In [16]:
# Create a base map
map_NRU = folium.Map(location=[43.6426, -79.3871], 
                 tiles='cartodbpositron',
                 zoom_start=10)

# Add a choropleth map to the base map
Choropleth(geo_data=plot_geography.__geo_interface__, 
           columns=['name', 'Rider Utilization'],
           data=plot_data, 
           key_on='feature.id', 
           fill_color='YlOrRd', 
           legend_name='Rider Utilization Ratio'
          ).add_to(map_NRU)

# Display the map
map_NRU
Out[16]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Note: blacked out areas are neighborhoods that do not have bike stations
Note: high RU area is skewing the scale

In [17]:
neigh_RU
Out[17]:
name geometry Rider Utilization
0 Wychwood POLYGON ((626071.503 4837537.756, 626151.708 4... 0.011350
1 Yonge-Eglinton POLYGON ((628032.302 4840233.689, 628139.346 4... 0.017046
2 Yonge-St.Clair POLYGON ((629674.232 4837709.743, 629657.497 4... 0.005554
3 York University Heights POLYGON ((620320.085 4846288.688, 620352.534 4... 0.001706
4 Yorkdale-Glen Park POLYGON ((625714.291 4840359.316, 625680.263 4... NaN
... ... ... ...
135 Kennedy Park POLYGON ((641302.092 4843448.098, 641297.809 4... NaN
136 Kensington-Chinatown POLYGON ((628713.653 4833925.535, 628698.164 4... 0.080993
137 Kingsview Village-The Westway POLYGON ((616628.923 4840623.278, 616634.524 4... NaN
138 Kingsway South POLYGON ((619601.263 4833636.747, 619589.120 4... 0.002312
139 L'Amoreaux POLYGON ((637682.073 4850646.444, 637631.392 4... NaN

140 rows × 3 columns

In [18]:
# threshold = median of Bike_Census_Utilization data
color_thresh = 0.004162
NaN_Good_N = []

for RU in neigh_RU['Rider Utilization']:
    if RU >= color_thresh:
        NaN_Good_N.append(1)
    elif RU >= 0:
        NaN_Good_N.append(0)
    else:
        NaN_Good_N.append(None)

NaN_Good_N_df = pd.DataFrame(data = NaN_Good_N, columns = ['Color Code'])
NaN_Good_N_df.head()
Out[18]:
Color Code
0 1.0
1 1.0
2 1.0
3 0.0
4 NaN
In [19]:
color_code_NRU = neigh_RU.merge(NaN_Good_N_df, how = "left", left_index = True, right_index = True)
color_code_NRU.head()
Out[19]:
name geometry Rider Utilization Color Code
0 Wychwood POLYGON ((626071.503 4837537.756, 626151.708 4... 0.011350 1.0
1 Yonge-Eglinton POLYGON ((628032.302 4840233.689, 628139.346 4... 0.017046 1.0
2 Yonge-St.Clair POLYGON ((629674.232 4837709.743, 629657.497 4... 0.005554 1.0
3 York University Heights POLYGON ((620320.085 4846288.688, 620352.534 4... 0.001706 0.0
4 Yorkdale-Glen Park POLYGON ((625714.291 4840359.316, 625680.263 4... NaN NaN
In [20]:
# make plot with threshold = median RU
# Create a base map
map_NRU_2 = folium.Map(location=[43.6426, -79.3871], 
                 tiles='cartodbpositron',
                 zoom_start=10)

# Add a choropleth map to the base map
Choropleth(geo_data=plot_geography.__geo_interface__, 
           columns=['name', 'Color Code'],
           data=color_code_NRU, 
           key_on='feature.id', 
           fill_color='RdYlGn',
           legend_name='Rider Utilization'
          ).add_to(map_NRU_2)

# Display the map
map_NRU_2
Out[20]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [21]:
# count good and bad neighborhoods
Ngood = 0
Nbad = 0
Nnan = 0

for code in NaN_Good_N_df['Color Code']:
    if code == 1.0:
        Ngood = Ngood+1
    elif code == 0.0:
        Nbad = Nbad+1
    else:
        Nnan = Nnan+1

print(Ngood)
print(Nbad)
print(Nnan)
38
35
67
In [22]:
# make plots w thresh = IQR -> 'good' = in range = 0.5 (yellow), 'bad' is outside = 0 (red) and 1 (green)
In [38]:
# threshold = interquartile range of of Bike_Census_Utilization data
Tlow = 0.001931092534540725
Thigh = 0.0123294014195088
IQR_N = []

for RU in neigh_RU['Rider Utilization']:
    if RU >= Tlow and RU <= Thigh:
        IQR_N.append(0.5)
    elif RU < Tlow:
        IQR_N.append(0)
    elif RU > Thigh:
        IQR_N.append(1)
    else:
        IQR_N.append(None)

IQR_N_df = pd.DataFrame(data = IQR_N, columns = ['Color Code'])
IQR_N_df.head()
Out[38]:
Color Code
0 0.5
1 1.0
2 0.5
3 0.0
4 NaN
In [39]:
IQR_CC_NRU = neigh_RU.merge(IQR_N_df, how = "left", left_index = True, right_index = True)
IQR_CC_NRU.head()
Out[39]:
name geometry Rider Utilization Color Code
0 Wychwood POLYGON ((626071.503 4837537.756, 626151.708 4... 0.011350 0.5
1 Yonge-Eglinton POLYGON ((628032.302 4840233.689, 628139.346 4... 0.017046 1.0
2 Yonge-St.Clair POLYGON ((629674.232 4837709.743, 629657.497 4... 0.005554 0.5
3 York University Heights POLYGON ((620320.085 4846288.688, 620352.534 4... 0.001706 0.0
4 Yorkdale-Glen Park POLYGON ((625714.291 4840359.316, 625680.263 4... NaN NaN
In [40]:
# make plot with threshold = IQR RU
# Create a base map
map_NRU_3 = folium.Map(location=[43.6426, -79.3871], 
                 tiles='cartodbpositron',
                 zoom_start=10)

# Add a choropleth map to the base map
Choropleth(geo_data=plot_geography.__geo_interface__, 
           columns=['name', 'Color Code'],
           data=IQR_CC_NRU, 
           key_on='feature.id', 
           fill_color='RdYlGn',
           legend_name='Rider Utilization'
          ).add_to(map_NRU_3)

# Display the map
map_NRU_3
Out[40]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [41]:
# count neighborhoods classifications
Nunder = 0
Ngood_2 = 0
Nover = 0
Nnan_2 = 0

for code in IQR_N_df['Color Code']:
    if code == 1.0:
        Nover = Nover+1
    elif code == 0.5:
        Ngood_2 = Ngood_2+1
    elif code == 0.0:
        Nunder = Nunder+1
    else:
        Nnan_2 = Nnan_2+1

print(Nover)
print(Ngood_2)
print(Nunder)
print(Nnan_2)
18
34
21
67

plot the number of stations that need to be added

In [27]:
# load reccomendation file
bike_rec = pd.read_csv('recommendations.csv')
bike_rec.head()
Out[27]:
Unnamed: 0 Neighbourhood Bike spots addition
0 0 Westminster-Branson 104
1 1 Rockcliffe-Smythe 89
2 2 Birchcliffe-Cliffside 85
3 3 Stonegate-Queensway 76
4 4 Humewood-Cedarvale 75
In [28]:
bike_rec = bike_rec.drop(columns = ["Unnamed: 0"])
bike_rec.head()
Out[28]:
Neighbourhood Bike spots addition
0 Westminster-Branson 104
1 Rockcliffe-Smythe 89
2 Birchcliffe-Cliffside 85
3 Stonegate-Queensway 76
4 Humewood-Cedarvale 75
In [29]:
# merge the bike recs with the neighborhood info
bike_rec_neigh = bike_rec.merge(neighbourhoods, how = "left", left_on = "Neighbourhood", right_on = "name")
bike_rec_neigh.head()
Out[29]:
Neighbourhood Bike spots addition name geometry
0 Westminster-Branson 104 Westminster-Branson POLYGON ((625533.338 4846776.345, 625568.712 4...
1 Rockcliffe-Smythe 89 Rockcliffe-Smythe POLYGON ((619956.573 4835478.816, 619940.466 4...
2 Birchcliffe-Cliffside 85 Birchcliffe-Cliffside POLYGON ((638310.304 4837852.879, 638297.906 4...
3 Stonegate-Queensway 76 Stonegate-Queensway POLYGON ((621566.778 4833819.469, 621555.433 4...
4 Humewood-Cedarvale 75 Humewood-Cedarvale POLYGON ((627468.976 4837950.463, 627417.700 4...
In [30]:
bike_rec_neigh = bike_rec_neigh.drop(columns = ["name"])
bike_rec_neigh.head()
Out[30]:
Neighbourhood Bike spots addition geometry
0 Westminster-Branson 104 POLYGON ((625533.338 4846776.345, 625568.712 4...
1 Rockcliffe-Smythe 89 POLYGON ((619956.573 4835478.816, 619940.466 4...
2 Birchcliffe-Cliffside 85 POLYGON ((638310.304 4837852.879, 638297.906 4...
3 Stonegate-Queensway 76 POLYGON ((621566.778 4833819.469, 621555.433 4...
4 Humewood-Cedarvale 75 POLYGON ((627468.976 4837950.463, 627417.700 4...
In [31]:
# make plot with number of bikes to add
# Create a base map
map_NRU_4 = folium.Map(location=[43.6426, -79.3871], 
                 tiles='cartodbpositron',
                 zoom_start=10)

# Add a choropleth map to the base map
Choropleth(geo_data=plot_geography.__geo_interface__, 
           columns=['Neighbourhood', 'Bike spots addition'],
           data=bike_rec_neigh, 
           key_on='feature.id', 
           fill_color='RdYlGn_r',
           legend_name='Number of Bikes'
          ).add_to(map_NRU_4)

# Display the map
map_NRU_4
Out[31]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [ ]:
 
In [42]:
neigh_bikerec = IQR_CC_NRU.merge(bike_rec, how = "left", left_on = "name", right_on = "Neighbourhood")
neigh_bikerec.head()
Out[42]:
name geometry Rider Utilization Color Code Neighbourhood Bike spots addition
0 Wychwood POLYGON ((626071.503 4837537.756, 626151.708 4... 0.011350 0.5 NaN NaN
1 Yonge-Eglinton POLYGON ((628032.302 4840233.689, 628139.346 4... 0.017046 1.0 NaN NaN
2 Yonge-St.Clair POLYGON ((629674.232 4837709.743, 629657.497 4... 0.005554 0.5 NaN NaN
3 York University Heights POLYGON ((620320.085 4846288.688, 620352.534 4... 0.001706 0.0 York University Heights 43.0
4 Yorkdale-Glen Park POLYGON ((625714.291 4840359.316, 625680.263 4... NaN NaN NaN NaN
In [43]:
neigh_bikerec = neigh_bikerec.drop(columns = ["Neighbourhood"])
In [44]:
neigh_bikerec['BSA isnull'] = neigh_bikerec['Bike spots addition'].isnull()
In [45]:
neigh_bikerec.info()
<class 'geopandas.geodataframe.GeoDataFrame'>
Int64Index: 140 entries, 0 to 139
Data columns (total 6 columns):
 #   Column               Non-Null Count  Dtype   
---  ------               --------------  -----   
 0   name                 140 non-null    object  
 1   geometry             140 non-null    geometry
 2   Rider Utilization    73 non-null     float64 
 3   Color Code           73 non-null     float64 
 4   Bike spots addition  18 non-null     float64 
 5   BSA isnull           140 non-null    bool    
dtypes: bool(1), float64(3), geometry(1), object(1)
memory usage: 6.7+ KB
In [46]:
for index, BSANaN in enumerate(neigh_bikerec['BSA isnull']):
    if BSANaN == True:
        CC = neigh_bikerec['Color Code'].iloc[index]
        if CC == 1.0 or CC == 0.5:
            neigh_bikerec['Bike spots addition'].iloc[index] = 0
            
neigh_bikerec.head()
Out[46]:
name geometry Rider Utilization Color Code Bike spots addition BSA isnull
0 Wychwood POLYGON ((626071.503 4837537.756, 626151.708 4... 0.011350 0.5 0.0 True
1 Yonge-Eglinton POLYGON ((628032.302 4840233.689, 628139.346 4... 0.017046 1.0 0.0 True
2 Yonge-St.Clair POLYGON ((629674.232 4837709.743, 629657.497 4... 0.005554 0.5 0.0 True
3 York University Heights POLYGON ((620320.085 4846288.688, 620352.534 4... 0.001706 0.0 43.0 False
4 Yorkdale-Glen Park POLYGON ((625714.291 4840359.316, 625680.263 4... NaN NaN NaN True
In [47]:
# make plot with number of bikes to add
# Create a base map
map_NRU_5 = folium.Map(location=[43.6426, -79.3871], 
                 tiles='cartodbpositron',
                 zoom_start=10)

# Add a choropleth map to the base map
Choropleth(geo_data=plot_geography.__geo_interface__, 
           columns=['name', 'Bike spots addition'],
           data=neigh_bikerec, 
           key_on='feature.id', 
           fill_color='RdYlGn_r',
           legend_name='Number of Bikes'
          ).add_to(map_NRU_5)

# Display the map
map_NRU_5
Out[47]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [ ]:
 
In [55]:
rec_percent = pd.read_csv('recommendations_bad.csv')
rec_percent.head()
Out[55]:
Unnamed: 0 Neighbourhood Bike spots addition Bike spots % change
0 0 Westminster-Branson 104 274
1 1 Rockcliffe-Smythe 89 473
2 2 Birchcliffe-Cliffside 85 386
3 3 Stonegate-Queensway 76 181
4 4 Humewood-Cedarvale 75 209
In [56]:
rec_percent.shape
Out[56]:
(18, 4)
In [57]:
rec_percent = rec_percent[rec_percent['Bike spots % change'] >= 0]
rec_percent.shape
Out[57]:
(18, 4)
In [58]:
map_NRU_6 = folium.Map(location=[43.6426, -79.3871], 
                 tiles='cartodbpositron',
                 zoom_start=10)

# Add a choropleth map to the base map
Choropleth(geo_data=plot_geography.__geo_interface__, 
           columns=['Neighbourhood', 'Bike spots % change'],
           data=rec_percent, 
           key_on='feature.id', 
           fill_color='RdYlGn_r',
           legend_name='Number of Bikes (%)'
          ).add_to(map_NRU_6)

# Display the map
map_NRU_6
Out[58]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [60]:
map_NRU_7 = folium.Map(location=[43.6426, -79.3871], 
                 tiles='cartodbpositron',
                 zoom_start=10)

# Add a choropleth map to the base map
Choropleth(geo_data=plot_geography.__geo_interface__, 
           columns=['Neighbourhood', 'Bike spots addition'],
           data=rec_percent, 
           key_on='feature.id', 
           fill_color='RdYlGn_r',
           legend_name='Number of Bikes'
          ).add_to(map_NRU_7)

# Display the map
map_NRU_7
Out[60]:
Make this Notebook Trusted to load map: File -> Trust Notebook